#pragma once

#include <AVUIVisual.h>
#include <AVUIRect3D.h>

namespace AVUI {
class BitmapEffect;
class BitmapEffectInput;
class DrawingGroup;
class DoubleCollection;
class HitTestParameters3D;
class Visual3D;
class Geometry;

/// <summary>Provides utility methods that perform common tasks involving nodes in a visual tree.</summary>
class VisualTreeHelper
{
public:
#pragma region Public Methods

    /// <summary>Returns the <see cref="T:System.Windows.Media.Effects.BitmapEffect" /> value for the specified <see cref="T:System.Windows.Media.Visual" />.</summary>
    /// <returns>The <see cref="T:System.Windows.Media.Effects.BitmapEffect" /> for this <see cref="T:System.Windows.Media.Visual" />.</returns>
    /// <param name="reference">The <see cref="T:System.Windows.Media.Visual" /> that contains the bitmap effect.</param>
    static BitmapEffect* GetBitmapEffect(Visual* pReference);

    /// <summary>Returns the <see cref="T:System.Windows.Media.Effects.BitmapEffectInput" /> value for the specified <see cref="T:System.Windows.Media.Visual" />.</summary>
    /// <returns>The <see cref="T:System.Windows.Media.Effects.BitmapEffectInput" /> for this <see cref="T:System.Windows.Media.Visual" />.</returns>
    /// <param name="reference">The <see cref="T:System.Windows.Media.Visual" /> that contains the bitmap effect input value.</param>
    static BitmapEffectInput* GetBitmapEffectInput(Visual* pReference);

    /// <summary>Returns the child visual object from the specified collection index within a specified parent.</summary>
    /// <returns>The index value of the child visual object.</returns>
    /// <param name="reference">The parent visual, referenced as a <see cref="T:System.Windows.DependencyObject" />.</param>
    /// <param name="childIndex">The index that represents the child visual that is contained by <paramref name="reference" />.</param>
    static DependencyObject* GetChild(DependencyObject* pReference, int childIndex);

    /// <summary>Returns the number of children that the specified visual object contains.</summary>
    /// <returns>The number of child visuals that the parent visual contains.</returns>
    /// <param name="reference">The parent visual that is referenced as a <see cref="T:System.Windows.DependencyObject" />.</param>
    static int GetChildrenCount(DependencyObject* pReference);

    /// <summary>Return the clip region of the specified <see cref="T:System.Windows.Media.Visual" /> as a <see cref="T:System.Windows.Media.Geometry" /> value.</summary>
    /// <returns>The clip region value of the <see cref="T:System.Windows.Media.Visual" /> returned as a <see cref="T:System.Windows.Media.Geometry" /> type.</returns>
    /// <param name="reference">The <see cref="T:System.Windows.Media.Visual" /> whose clip region value is returned.</param>
    static Geometry* GetClip(Visual* pReference);

    /// <summary>Returns the cached bounding box rectangle for the specified <see cref="T:System.Windows.Media.Media3D.Visual3D" />.</summary>
    /// <returns>The bounding box 3D rectangle for the <see cref="T:System.Windows.Media.Media3D.Visual3D" />.</returns>
    /// <param name="reference">The 3D visual whose bounding box value is computed.</param>
    static Rect3D GetContentBounds(Visual3D* pReference);

    /// <summary>Returns the cached bounding box rectangle for the specified <see cref="T:System.Windows.Media.Visual" />.</summary>
    /// <returns>The bounding box rectangle for the <see cref="T:System.Windows.Media.Visual" />.</returns>
    /// <param name="reference">The <see cref="T:System.Windows.Media.Visual" /> whose bounding box value is computed.</param>
    static Rect GetContentBounds(Visual* pReference);

    /// <summary>Returns the union of all the content bounding boxes for all the descendants of the specified <see cref="T:System.Windows.Media.Media3D.Visual3D" />, which includes the content bounding box of the <see cref="T:System.Windows.Media.Media3D.Visual3D" />.</summary>
    /// <returns>Returns the bounding box 3D rectangle for the 3D visual.</returns>
    /// <param name="reference">The 3D visual whose bounding box value for all descendants is computed.</param>
    static Rect3D GetDescendantBounds(Visual3D* pReference);

    /// <summary>Returns the union of all the content bounding boxes for all the descendants of the <see cref="T:System.Windows.Media.Visual" />, which includes the content bounding box of the <see cref="T:System.Windows.Media.Visual" />.</summary>
    /// <returns>The bounding box rectangle for the specified <see cref="T:System.Windows.Media.Visual" />.</returns>
    /// <param name="reference">The <see cref="T:System.Windows.Media.Visual" /> whose bounding box value for all descendants is computed.</param>
    static Rect GetDescendantBounds(Visual* pReference);

    /// <summary>Returns the drawing content of the specified <see cref="T:System.Windows.Media.Visual" />.</summary>
    /// <returns>The drawing content of the <see cref="T:System.Windows.Media.Visual" /> returned as a <see cref="T:System.Windows.Media.DrawingGroup" /> type.</returns>
    /// <param name="reference">The <see cref="T:System.Windows.Media.Visual" /> whose drawing content is returned.</param>
    static DrawingGroup* GetDrawing(Visual* pReference);

    /// <summary>Returns the edge mode of the specified <see cref="T:System.Windows.Media.Visual" /> as an <see cref="T:System.Windows.Media.EdgeMode" /> value.</summary>
    /// <returns>The <see cref="T:System.Windows.Media.EdgeMode" /> value of the <see cref="T:System.Windows.Media.Visual" />.</returns>
    /// <param name="reference">The <see cref="T:System.Windows.Media.Visual" /> whose edge mode value is returned.</param>
    static EdgeMode::Enum GetEdgeMode(Visual* pReference);

    /// <summary>Returns the offset of the <see cref="T:System.Windows.Media.Visual" />.</summary>
    /// <returns>A <see cref="T:System.Windows.Vector" /> that represents the offset value of the <see cref="T:System.Windows.Media.Visual" />.</returns>
    /// <param name="reference">The <see cref="T:System.Windows.Media.Visual" /> whose offset is returned.</param>
    static Vector GetOffset(Visual* pReference);

    /// <summary>Returns the opacity of the <see cref="T:System.Windows.Media.Visual" />.</summary>
    /// <returns>A value of type <see cref="T:System.Double" /> that represents the opacity value of the <see cref="T:System.Windows.Media.Visual" />.</returns>
    /// <param name="reference">The <see cref="T:System.Windows.Media.Visual" /> whose opacity value is returned.</param>
    static float GetOpacity(Visual* pReference);

    /// <summary>Returns a <see cref="T:System.Windows.Media.Brush" /> value that represents the opacity mask of the <see cref="T:System.Windows.Media.Visual" />.</summary>
    /// <returns>A value of type <see cref="T:System.Windows.Media.Brush" /> that represents the opacity mask value of the <see cref="T:System.Windows.Media.Visual" />.</returns>
    /// <param name="reference">The <see cref="T:System.Windows.Media.Visual" /> whose opacity mask value is returned.</param>
    static Brush* GetOpacityMask(Visual* pReference);

    /// <summary>Returns a <see cref="T:System.Windows.DependencyObject" /> value that represents the parent of the visual object.</summary>
    /// <returns>The parent of the visual.</returns>
    /// <param name="reference">The visual whose parent is returned.</param>
    static DependencyObject* GetParent(DependencyObject* pReference);

    /// <summary>Returns a <see cref="T:System.Windows.Media.Transform" /> value for the <see cref="T:System.Windows.Media.Visual" />.</summary>
    /// <returns>The transform value of the <see cref="T:System.Windows.Media.Visual" />, or null if <paramref name="reference" /> does not have a transform defined.</returns>
    /// <param name="reference">The <see cref="T:System.Windows.Media.Visual" /> whose transform value is returned.</param>
    static Transform* GetTransform(Visual* pReference);

    /// <summary>Returns an X-coordinate (vertical) guideline collection.</summary>
    /// <returns>The X-coordinate guideline collection of the <see cref="T:System.Windows.Media.Visual" />.</returns>
    /// <param name="reference">The <see cref="T:System.Windows.Media.Visual" /> whose X-coordinate guideline collection is returned.</param>
    static DoubleCollection* GetXSnappingGuidelines(Visual* pReference);

    /// <summary>Returns a Y-coordinate (horizontal) guideline collection.</summary>
    /// <returns>The Y-coordinate guideline collection of the <see cref="T:System.Windows.Media.Visual" />.</returns>
    /// <param name="reference">The <see cref="T:System.Windows.Media.Visual" /> whose Y-coordinate guideline collection is returned.</param>
    static DoubleCollection* GetYSnappingGuidelines(Visual* pReference);

    /// <summary>Returns the topmost <see cref="T:System.Windows.Media.Visual" /> object of a hit test by specifying a <see cref="T:System.Windows.Point" />.</summary>
    /// <returns>The hit test result of the <see cref="T:System.Windows.Media.Visual" />, returned as a <see cref="T:System.Windows.Media.HitTestResult" /> type.</returns>
    /// <param name="reference">The <see cref="T:System.Windows.Media.Visual" /> to hit test.</param>
    /// <param name="point">The point value to hit test against.</param>
    static TRefCountedPtr<HitTestResult> HitTest(Visual* pReference, const Point& point);

    /// <summary>Initiates a hit test on the specified <see cref="T:System.Windows.Media.Media3D.Visual3D" />, with caller-defined <see cref="T:System.Windows.Media.HitTestFilterCallback" /> and <see cref="T:System.Windows.Media.HitTestResultCallback" /> methods.</summary>
    /// <param name="reference">The <see cref="T:System.Windows.Media.Media3D.Visual3D" /> to hit test.</param>
    /// <param name="filterCallback">The method that represents the hit test filter callback value.</param>
    /// <param name="resultCallback">The method that represents the hit test result callback value.</param>
    /// <param name="hitTestParameters">The 3D parameter value to hit test against.</param>
    static void HitTest(Visual3D* pReference, HitTestFilterCallback* pFilterCallback, HitTestResultCallback* pResultCallback, HitTestParameters3D* pHitTestParameters);

    /// <summary>Initiates a hit test on the specified <see cref="T:System.Windows.Media.Visual" />, with caller-defined <see cref="T:System.Windows.Media.HitTestFilterCallback" /> and <see cref="T:System.Windows.Media.HitTestResultCallback" /> methods.</summary>
    /// <param name="reference">The <see cref="T:System.Windows.Media.Visual" /> to hit test.</param>
    /// <param name="filterCallback">The method that represents the hit test filter callback value.</param>
    /// <param name="resultCallback">The method that represents the hit test result callback value.</param>
    /// <param name="hitTestParameters">The parameter value to hit test against.</param>
    static void HitTest(Visual* pReference, HitTestFilterCallback* pFilterCallback, HitTestResultCallback* pResultCallback, HitTestParameters* pHitTestParameters);

#pragma region Public Methods

public:
 
#pragma region Internal Methods

    static DependencyObject* FindCommonAncestor(DependencyObject* pReference, DependencyObject* pOtherVisual);
    static Visual* GetContainingVisual2D(DependencyObject* pReference);
    static Visual3D* GetContainingVisual3D(DependencyObject* pReference);
    static DependencyObject* GetParentInternal(DependencyObject* pReference);
    static TRefCountedPtr<HitTestResult> HitTest(Visual* pReference, const Point& point, bool include2DOn3D);
    static bool IsAncestorOf(DependencyObject* pReference, DependencyObject* pDescendant);

#pragma endregion Internal Methods
 
private:
 
#pragma region Private Methods

    static void CheckVisualReferenceArgument(DependencyObject* pReference);

#pragma endregion Private Methods

};
 
}; // namespace AVUI

